/* Hello World Example

   This example code is in the Public Domain (or CC0 licensed, at your option.)

   Unless required by applicable law or agreed to in writing, this
   software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
   CONDITIONS OF ANY KIND, either express or implied.
*/
#include <stdio.h>
#include "sdkconfig.h"

#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/event_groups.h"
#include "freertos/semphr.h"
#include "freertos/queue.h"

#include "esp_system.h"
#include "esp_wifi.h"

#include "esp_spi_flash.h"

#include "nvs_flash.h"
#include "nvs.h"
#include <string.h>
#include "lwip/err.h"
#include "lwip/sys.h"
#include "esp_event.h"
#include "esp_log.h"

#include <sys/param.h>
#include "esp_netif.h"
#include "esp_eth.h"

#include "esp_tls_crypto.h"
#include <esp_http_server.h>

#include "lwip/sockets.h"
#include "lwip/dns.h"
#include "lwip/netdb.h"

#include "mqtt_client.h"

#include "cJSON.h"

#include "driver/gpio.h"
#include "driver/adc.h"
#include "esp_adc_cal.h"

#include "driver/pcnt.h"

#include "driver/uart.h"

#include "esp_ota_ops.h"
#include "esp_http_client.h"
#include "esp_https_ota.h"
//掉电保存数据

/*STA默认配置*/
#define sta_wifi_name_size 32
char sta_wifi_name[sta_wifi_name_size];
#define EXAMPLE_ESP_STA_WIFI_SSID "unknown"

#define sta_wifi_password_size 64
char sta_wifi_password[sta_wifi_password_size];
#define EXAMPLE_ESP_STA_WIFI_PASS "12345678"

#define ap_wifi_name_size 32
char ap_wifi_name[ap_wifi_name_size];
#define EXAMPLE_ESP_AP_WIFI_SSID "ap_wifi123456"

#define ap_wifi_password_size 64
char ap_wifi_password[ap_wifi_password_size];
#define EXAMPLE_ESP_AP_WIFI_PASS "12345678"

#define Refrigerator_name_size 40
#define Refrigerator_name_define "冰箱名"
char Refrigerator_name[Refrigerator_name_size];

#define Serial_number_size 32
#define Serial_number_define "序列号"
char Serial_number[Serial_number_size];

int16_t Upper_temp_limit = 0; //温度上限
int16_t Lower_temp_limit = 0; //温度下限

int16_t temp_sim_Bias = 0;
int16_t temp_probe_Bias = 0;

int16_t protocol_485 = 0; // 485模式

#define mqtt_address_size 128
#define mqtt_address_define "192.168.1.88:1883"
char mqtt_address[mqtt_address_size];

#define mqtt_admin_size 128
#define mqtt_admin_define ""
char mqtt_admin[mqtt_admin_size];

#define mqtt_password_size 128
#define mqtt_password_define ""
char mqtt_password[mqtt_password_size];

#define mqtt_subscription_size 128
#define mqtt_subscription_define "emqx1"
char mqtt_subscription[mqtt_subscription_size];

#define mqtt_publish_size 128
#define mqtt_publish_define "queue"
char mqtt_publish[mqtt_publish_size];

int16_t temp_cail1 = 0;
int16_t temp_cail2 = 0;

#define refrigerator_username_size 128
#define refrigerator_username_define "冰箱用户名"
char refrigerator_username[refrigerator_username_size];

#define IP_address_size 20
#define IP_address_define ""
#define DNS_address_define ""
#define Subnet_mask_address_define ""
#define GW_address_define ""

uint8_t En_DHCP = 1;
char IP_address[IP_address_size];
char DNS_address[IP_address_size];
char Subnet_mask_address[IP_address_size];
char GW_address[IP_address_size];

#define Module_password_size 30
#define Module_password_default "123456"
char Module_password[Module_password_size];

/*WIFI 配置*/
#define ESP_WIFI_SCAN_AUTH_MODE_THRESHOLD WIFI_AUTH_OPEN
/*AP默认配置*/
#define EXAMPLE_ESP_AP_WIFI_CHANNEL 2
#define EXAMPLE_MAX_AP_STA_CONN 10

int temp_sim = 1000; //模拟物温度

int temp_probe = 1000; //监控探头温度

int temp_Sensor = 1000;

bool device_485_online = false;
bool device_485_compressor = false;
bool device_485_condenser = false;
bool device_485_evaporator = false;

bool Delay_alarm = false;
int Delay_alarm_time = -1;

int16_t temp_set = 0;                     //温度设置值
int16_t Control_return = 0;               //控制回差
int16_t compressor_min_start_time = 0;    //压缩机启动最小间隔时间
int16_t compressor_min_interval_time = 0; //压缩机首次启动最小间隔时间
int16_t Cabinet_temp_check = 0;           //柜温校正
int16_t temp_Lower_limit = 0;             //温度设置下限
int16_t temp_Lower_Upper = 0;             //温度设置上限
int16_t evaporator_temp_check = 0;        //蒸发器传感器温度校正
int16_t Defrosting_cycle = 0;             //除霜周期
int16_t Defrosting_max_time = 0;          //除霜最长时间
int16_t Defrosting_end_temp = 0;          //除霜终止温度
int16_t Defrosting_drip_time = 0;         //除霜后滴水时间
int16_t Defrosting_start_Fan_delay = 0;   //除霜后风机启动延时
int16_t Fahrenheit_Celsius = 0;           //华氏和摄氏选择
int16_t temp_cabinet_lower_limit = 0;     //柜温下限
int16_t temp_cabinet_upper_limit = 0;     //柜温上限

int16_t temp_box = 1000;        //箱内温度
int16_t temp_evaporator = 1000; //蒸发器温度

bool defrost_drip_state = false; //化霜滴水状态
bool Fan_state = false;          //风机状态
bool defrost_state = false;      //化霜状态
bool compressor_state = false;   //压缩机状态

bool cabinet_min_temp_warning = false; //柜温低温报警
bool cabinet_max_temp_warning = false; //柜温高温报警

bool Evaporation_sensor_fault = false; //蒸发传感器故障
bool cabinet_sensor_fault = false;     //柜温传感器故障

esp_mqtt_client_handle_t client1;
static void echo_send(const int port, const char *str, uint8_t length);

void app_nvs_flash_init(void)
{
    esp_err_t err = nvs_flash_init();
    if (err == ESP_ERR_NVS_NO_FREE_PAGES || err == ESP_ERR_NVS_NEW_VERSION_FOUND)
    {
        // NVS分区被截断，需要擦除并重新初始化
        ESP_ERROR_CHECK(nvs_flash_erase());
        err = nvs_flash_init();
    }
    ESP_ERROR_CHECK(err);

    nvs_handle_t my_handle;
    err = nvs_open("storage", NVS_READWRITE, &my_handle);
    if (err != ESP_OK)
    {
        // printf("Error (%s) opening NVS handle!\n", esp_err_to_name(err));
    }
    else
    {
        // nvs_erase_all(my_handle);
        size_t lenth = 0;
        if ((err = nvs_get_str(my_handle, "sta_wifi_name", NULL, &lenth)) == ESP_OK)
        {
            if ((err = nvs_get_str(my_handle, "sta_wifi_name", sta_wifi_name, &lenth)) == ESP_OK)
            {
            }
        }
        else
        {

            strcpy(sta_wifi_name, EXAMPLE_ESP_STA_WIFI_SSID);
        }

        if ((err = nvs_get_str(my_handle, "sta_pass", NULL, &lenth)) == ESP_OK)
        {
            if ((err = nvs_get_str(my_handle, "sta_pass", sta_wifi_password, &lenth)) == ESP_OK)
            {
            }
        }
        else
        {
            strcpy(sta_wifi_password, EXAMPLE_ESP_STA_WIFI_PASS);
        }

        if ((err = nvs_get_str(my_handle, "ap_name", NULL, &lenth)) == ESP_OK)
        {
            if ((err = nvs_get_str(my_handle, "ap_name", ap_wifi_name, &lenth)) == ESP_OK)
            {
                if (lenth == 0)
                {
                    strcpy(ap_wifi_name, EXAMPLE_ESP_AP_WIFI_SSID);
                }
            }
        }
        else
        {
            strcpy(ap_wifi_name, EXAMPLE_ESP_AP_WIFI_SSID);
        }
        if ((err = nvs_get_str(my_handle, "ap_password", NULL, &lenth)) == ESP_OK)
        {
            if ((err = nvs_get_str(my_handle, "ap_password", ap_wifi_password, &lenth)) == ESP_OK)
            {
            }
        }
        else
        {
            strcpy(ap_wifi_password, EXAMPLE_ESP_AP_WIFI_PASS);
        }

        if ((err = nvs_get_str(my_handle, "Refri_name", NULL, &lenth)) == ESP_OK)
        {
            if ((err = nvs_get_str(my_handle, "Refri_name", Refrigerator_name, &lenth)) == ESP_OK)
            {
            }
        }
        else
        {
            strcpy(Refrigerator_name, Refrigerator_name_define);
        }
        if ((err = nvs_get_str(my_handle, "Serial_number", NULL, &lenth)) == ESP_OK)
        {
            if ((err = nvs_get_str(my_handle, "Serial_number", Serial_number, &lenth)) == ESP_OK)
            {
            }
        }
        else
        {
            strcpy(Serial_number, Serial_number_define);
        }
        if ((err = nvs_get_i16(my_handle, "Up_temp_limit", &Upper_temp_limit)) == ESP_OK)
        {
        }

        if ((err = nvs_get_i32(my_handle, "Dela_ala_time", &Delay_alarm_time)) == ESP_OK)
        {
        }

        if ((err = nvs_get_i16(my_handle, "Lo_temp_limit", &Lower_temp_limit)) == ESP_OK)
        {
        }

        if ((err = nvs_get_i16(my_handle, "temp_sim_Bias", &temp_sim_Bias)) == ESP_OK)
        {
        }
        if ((err = nvs_get_i16(my_handle, "temp_pro_Bias", &temp_probe_Bias)) == ESP_OK)
        {
        }

        if ((err = nvs_get_i16(my_handle, "protocol_485", &protocol_485)) == ESP_OK)
        {
        }

        if ((err = nvs_get_str(my_handle, "mqtt_address", NULL, &lenth)) == ESP_OK)
        {
            if ((err = nvs_get_str(my_handle, "mqtt_address", mqtt_address, &lenth)) == ESP_OK)
            {
            }
        }
        else
        {
            strcpy(mqtt_address, mqtt_address_define);
        }
        if ((err = nvs_get_str(my_handle, "mqtt_admin", NULL, &lenth)) == ESP_OK)
        {
            if ((err = nvs_get_str(my_handle, "mqtt_admin", mqtt_admin, &lenth)) == ESP_OK)
            {
            }
        }
        else
        {
            strcpy(mqtt_admin, mqtt_admin_define);
        }
        if ((err = nvs_get_str(my_handle, "mqtt_password", NULL, &lenth)) == ESP_OK)
        {
            if ((err = nvs_get_str(my_handle, "mqtt_password", mqtt_password, &lenth)) == ESP_OK)
            {
            }
        }
        else
        {
            strcpy(mqtt_password, mqtt_password_define);
        }
        if ((err = nvs_get_str(my_handle, "mqtt_sub", NULL, &lenth)) == ESP_OK)
        {
            if ((err = nvs_get_str(my_handle, "mqtt_sub", mqtt_subscription, &lenth)) == ESP_OK)
            {
            }
        }
        else
        {
            strcpy(mqtt_subscription, mqtt_subscription_define);
        }
        if ((err = nvs_get_str(my_handle, "mqtt_publish", NULL, &lenth)) == ESP_OK)
        {
            if ((err = nvs_get_str(my_handle, "mqtt_publish", mqtt_publish, &lenth)) == ESP_OK)
            {
            }
        }
        else
        {
            strcpy(mqtt_publish, mqtt_publish_define);
        }
        if ((err = nvs_get_i16(my_handle, "temp_cail1", &temp_cail1)) == ESP_OK)
        {
        }

        if ((err = nvs_get_i16(my_handle, "temp_cail2", &temp_cail2)) == ESP_OK)
        {
        }

        if ((err = nvs_get_str(my_handle, "ref_username", NULL, &lenth)) == ESP_OK)
        {
            if ((err = nvs_get_str(my_handle, "ref_username", refrigerator_username, &lenth)) == ESP_OK)
            {
            }
        }
        else
        {
            strcpy(refrigerator_username, refrigerator_username_define);
        }
        if ((err = nvs_get_str(my_handle, "IP_address", NULL, &lenth)) == ESP_OK)
        {
            if ((err = nvs_get_str(my_handle, "IP_address", IP_address, &lenth)) == ESP_OK)
            {
            }
        }
        else
        {
            strcpy(IP_address, IP_address_define);
        }

        if ((err = nvs_get_str(my_handle, "DNS_address", NULL, &lenth)) == ESP_OK)
        {
            if ((err = nvs_get_str(my_handle, "DNS_address", DNS_address, &lenth)) == ESP_OK)
            {
            }
        }
        else
        {
            strcpy(DNS_address, DNS_address_define);
        }

        if ((err = nvs_get_str(my_handle, "GW_address", NULL, &lenth)) == ESP_OK)
        {
            if ((err = nvs_get_str(my_handle, "GW_address", GW_address, &lenth)) == ESP_OK)
            {
            }
        }
        else
        {
            strcpy(GW_address, GW_address_define);
        }

        if ((err = nvs_get_str(my_handle, "Smask_address", NULL, &lenth)) == ESP_OK)
        {
            if ((err = nvs_get_str(my_handle, "Smask_address", Subnet_mask_address, &lenth)) == ESP_OK)
            {
            }
        }
        else
        {
            strcpy(Subnet_mask_address, Subnet_mask_address_define);
        }

        if ((err = nvs_get_u8(my_handle, "En_DHCP", &En_DHCP)) == ESP_OK)
        {
        }
        else
        {
            En_DHCP = 1;
        }

        if ((err = nvs_get_str(my_handle, "Module_pass", NULL, &lenth)) == ESP_OK)
        {
            if ((err = nvs_get_str(my_handle, "Module_pass", Module_password, &lenth)) == ESP_OK)
            {
            }
        }
        else
        {
            strcpy(Module_password, Module_password_default);
        }
    }

    nvs_commit(my_handle);
}
void NVS_save()
{
    nvs_handle_t my_handle;
    esp_err_t err = nvs_open("storage", NVS_READWRITE, &my_handle);
    if (err != ESP_OK)
    {
        // printf("Error (%s) opening NVS handle!\n", esp_err_to_name(err));
    }
    else
    {
        nvs_set_str(my_handle, "sta_wifi_name", sta_wifi_name);
        nvs_set_str(my_handle, "sta_pass", sta_wifi_password);
        nvs_set_str(my_handle, "ap_name", ap_wifi_name);
        nvs_set_str(my_handle, "ap_password", ap_wifi_password);
        nvs_set_str(my_handle, "Refri_name", Refrigerator_name);
        nvs_set_str(my_handle, "Serial_number", Serial_number);

        nvs_set_i16(my_handle, "Up_temp_limit", Upper_temp_limit);
        nvs_set_i16(my_handle, "Lo_temp_limit", Lower_temp_limit);

        nvs_set_i32(my_handle, "Dela_ala_time", Delay_alarm_time);

        nvs_set_i16(my_handle, "temp_sim_Bias", temp_sim_Bias);
        nvs_set_i16(my_handle, "temp_pro_Bias", temp_probe_Bias);

        nvs_set_i16(my_handle, "protocol_485", protocol_485);

        nvs_set_str(my_handle, "mqtt_address", mqtt_address);
        nvs_set_str(my_handle, "mqtt_admin", mqtt_admin);
        nvs_set_str(my_handle, "mqtt_password", mqtt_password);
        nvs_set_str(my_handle, "mqtt_sub", mqtt_subscription);
        nvs_set_str(my_handle, "mqtt_publish", mqtt_publish);

        nvs_set_i16(my_handle, "temp_cail1", temp_cail1);
        nvs_set_i16(my_handle, "temp_cail2", temp_cail2);

        nvs_set_str(my_handle, "ref_username", refrigerator_username);
        nvs_set_str(my_handle, "IP_address", IP_address);

        nvs_set_str(my_handle, "DNS_address", DNS_address);

        nvs_set_str(my_handle, "GW_address", GW_address);
        nvs_set_str(my_handle, "Smask_address", Subnet_mask_address);

        nvs_set_u8(my_handle, "En_DHCP", En_DHCP);

        nvs_set_str(my_handle, "Module_pass", Module_password);
    }
    nvs_commit(my_handle);
}
static const char *TAG = "wifi softAP123";

//esp_err_t do_firmware_upgrade();
static void event_handler(void *arg, esp_event_base_t event_base,
                          int32_t event_id, void *event_data)
{
    if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_START)
    {
        //开始连接
        esp_wifi_connect();
    }
    else if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_DISCONNECTED)
    {
        //开始重连wifi
        esp_wifi_connect();
    }
    else if (event_base == IP_EVENT && event_id == IP_EVENT_STA_GOT_IP)
    {
        //连接成功
        // ip_event_got_ip_t *event = (ip_event_got_ip_t *)event_data;
        // printf("STA连接成功");

        /* code */
        // vTaskDelay(pdMS_TO_TICKS(100));
        // do_firmware_upgrade();
    }
    if (event_id == WIFI_EVENT_AP_STACONNECTED)
    {
        // ap
        // wifi_event_ap_staconnected_t *event = (wifi_event_ap_staconnected_t *)event_data;
    }
    else if (event_id == WIFI_EVENT_AP_STADISCONNECTED)
    {
        // ap
        // wifi_event_ap_stadisconnected_t *event = (wifi_event_ap_stadisconnected_t *)event_data;
    }
}
bool IPv4_verify2(char *ip)
{
    int a, b, c, d;
    char i = sscanf(ip, "%d.%d.%d.%d", &a, &b, &c, &d);
    if (4 == i)
    {
        if (0 <= a && a <= 255 && 0 <= b && b <= 255 && 0 <= c && c <= 255 && 0 <= d && d <= 255)
        {
            return true;
        }
    }
    return false;
}
void wifi_init_apsta(void)
{
    // s_wifi_event_group = xEventGroupCreate();

    ESP_ERROR_CHECK(esp_netif_init());
    ESP_ERROR_CHECK(esp_event_loop_create_default());
    esp_netif_create_default_wifi_ap();

    esp_netif_t *netif = esp_netif_create_default_wifi_sta();
    if (En_DHCP == 0)
    {
        if (IPv4_verify2(IP_address))
            if (IPv4_verify2(GW_address))
                if (IPv4_verify2(Subnet_mask_address))
                    if (IPv4_verify2(DNS_address))
                    {
                        esp_netif_dhcpc_stop(netif);
                        esp_netif_ip_info_t info_t = {0};

                        int a, b, c, d;
                        sscanf(IP_address, "%d.%d.%d.%d", &a, &b, &c, &d);
                        info_t.ip.addr = ESP_IP4TOADDR(a, b, c, d);

                        sscanf(GW_address, "%d.%d.%d.%d", &a, &b, &c, &d);
                        info_t.gw.addr = ESP_IP4TOADDR(a, b, c, d);

                        sscanf(Subnet_mask_address, "%d.%d.%d.%d", &a, &b, &c, &d);
                        info_t.netmask.addr = ESP_IP4TOADDR(a, b, c, d);

                        esp_netif_set_ip_info(netif, &info_t);

                        sscanf(DNS_address, "%d.%d.%d.%d", &a, &b, &c, &d);
                        esp_netif_dns_info_t dns;
                        dns.ip.u_addr.ip4.addr = ESP_IP4TOADDR(a, b, c, d);
                        dns.ip.type = IPADDR_TYPE_V4;
                        esp_netif_set_dns_info(netif, ESP_NETIF_DNS_MAIN, &dns);
                    }
    }

    wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT();
    ESP_ERROR_CHECK(esp_wifi_init(&cfg));

    ESP_ERROR_CHECK(esp_event_handler_instance_register(WIFI_EVENT,
                                                        ESP_EVENT_ANY_ID,
                                                        &event_handler,
                                                        NULL,
                                                        NULL));
    esp_event_handler_instance_t instance_any_id;
    esp_event_handler_instance_t instance_got_ip;
    ESP_ERROR_CHECK(esp_event_handler_instance_register(WIFI_EVENT,
                                                        ESP_EVENT_ANY_ID,
                                                        &event_handler,
                                                        NULL,
                                                        &instance_any_id));
    ESP_ERROR_CHECK(esp_event_handler_instance_register(IP_EVENT,
                                                        IP_EVENT_STA_GOT_IP,
                                                        &event_handler,
                                                        NULL,
                                                        &instance_got_ip));

    ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_APSTA));

    wifi_config_t wifi_config = {
        .sta = {
            // .ssid = sta_wifi_name,
            // .password = sta_wifi_password,
            /* Setting a password implies station will connect to all security modes including WEP/WPA.
             * However these modes are deprecated and not advisable to be used. Incase your Access point
             * doesn't support WPA2, these mode can be enabled by commenting below line */
            .threshold.authmode = ESP_WIFI_SCAN_AUTH_MODE_THRESHOLD,
        },
    };

    strcpy((char *)wifi_config.sta.ssid, sta_wifi_name);
    strcpy((char *)wifi_config.sta.password, sta_wifi_password);

    ESP_ERROR_CHECK(esp_wifi_set_config(WIFI_IF_STA, &wifi_config));
    wifi_config_t wifi_config1 = {
        .ap = {
            // .ssid = EXAMPLE_ESP_WIFI_SSID,
            // .ssid_len = strlen(EXAMPLE_ESP_WIFI_SSID),
            // .password = EXAMPLE_ESP_WIFI_PASS,
            .channel = EXAMPLE_ESP_AP_WIFI_CHANNEL,
            .max_connection = EXAMPLE_MAX_AP_STA_CONN,
            .authmode = WIFI_AUTH_WPA_WPA2_PSK},
    };
    strcpy((char *)wifi_config1.ap.ssid, ap_wifi_name);
    wifi_config1.ap.ssid_len = strlen(ap_wifi_name);
    strcpy((char *)wifi_config1.ap.password, ap_wifi_password);

    ESP_ERROR_CHECK(esp_wifi_set_config(WIFI_IF_AP, &wifi_config1));

    ESP_ERROR_CHECK(esp_wifi_start());
}
bool Modbus_write(int16_t address, int16_t data1);
static void mqtt_event_handler(void *handler_args, esp_event_base_t base, int32_t event_id, void *event_data)
{
    esp_mqtt_event_handle_t event = event_data;
    esp_mqtt_client_handle_t client = event->client;
    // int msg_id;
    switch ((esp_mqtt_event_id_t)event_id)
    {
    case MQTT_EVENT_CONNECTED:

        // if (strlen(mqtt_publish) != 0)
        // {
        //     esp_mqtt_client_publish(client, mqtt_publish, "data_3", 0, 1, 0);
        // }

        if (strlen(mqtt_subscription) != 0)
        {
            esp_mqtt_client_subscribe(client, mqtt_subscription, 0);
        }
        break;
    case MQTT_EVENT_DISCONNECTED:
        // ESP_LOGI(TAG, "MQTT_EVENT_DISCONNECTED");
        break;

    case MQTT_EVENT_SUBSCRIBED:
        // ESP_LOGI(TAG, "MQTT_EVENT_SUBSCRIBED, msg_id=%d", event->msg_id);
        // msg_id = esp_mqtt_client_publish(client, mqtt_publish, "data", 0, 0, 0);
        // ESP_LOGI(TAG, "sent publish successful, msg_id=%d", msg_id);
        break;
    case MQTT_EVENT_UNSUBSCRIBED:
        // ESP_LOGI(TAG, "MQTT_EVENT_UNSUBSCRIBED, msg_id=%d", event->msg_id);
        break;
    case MQTT_EVENT_PUBLISHED:
        // ESP_LOGI(TAG, "MQTT_EVENT_PUBLISHED, msg_id=%d", event->msg_id);
        break;
    case MQTT_EVENT_DATA:
        // mqtt接收数据
        printf("TOPIC=%.*s\r\n", event->topic_len, event->topic);
        printf("DATA=%.*s\r\n", event->data_len, event->data);
        if (protocol_485 == 0)
        {
            echo_send(UART_NUM_1, event->data, event->data_len);
        }
        else if (protocol_485 == 1)
        {
            switch (event->data[0])
            {
            case 0: //温度设置
                Modbus_write(0x0100, (event->data[1] << 8) + event->data[2]);
                break;
            case 1: //控制回差
                Modbus_write(0x0102, (event->data[1] << 8) + event->data[2]);
                break;
            case 2: //压缩机启动最小间隔时间单位分钟
                Modbus_write(0x0103, (event->data[1] << 8) + event->data[2]);
                break;
            case 3: //压缩机首次启动最小间隔时间单位分钟
                Modbus_write(0x0104, (event->data[1] << 8) + event->data[2]);
                break;
            case 4: //柜温传感器校正
                Modbus_write(0x0105, (event->data[1] << 8) + event->data[2]);
                break;
            case 5: //温度设置下限
                Modbus_write(0x0106, (event->data[1] << 8) + event->data[2]);
                break;
            case 6: //温度设置上限
                Modbus_write(0x0107, (event->data[1] << 8) + event->data[2]);
                break;
            case 7: //蒸发器传感器温度校正
                Modbus_write(0x010a, (event->data[1] << 8) + event->data[2]);
                break;
            case 8: //除霜周期
                Modbus_write(0x010b, (event->data[1] << 8) + event->data[2]);
                break;
            case 9: //除霜最长时间
                Modbus_write(0x010c, (event->data[1] << 8) + event->data[2]);
                break;

            case 10: //除霜终止温度
                Modbus_write(0x010d, (event->data[1] << 8) + event->data[2]);
                break;
            case 11: //除霜后滴水时间
                Modbus_write(0x010e, (event->data[1] << 8) + event->data[2]);
                break;
            case 12: //除霜后风机启动延时
                Modbus_write(0x0112, (event->data[1] << 8) + event->data[2]);
                break;
            case 13: //华氏和摄氏选择
                Modbus_write(0x040d, (event->data[1] << 8) + event->data[2]);
                break;
            case 14: //柜温下限
                Modbus_write(0x0117, (event->data[1] << 8) + event->data[2]);
                break;
            case 15: //柜温上限
                Modbus_write(0x0118, (event->data[1] << 8) + event->data[2]);
                break;
            case 16: //开关机0为关机1为开机
                Modbus_write(0x040e, (event->data[1] << 8) + event->data[2]);
                break;

            default:
                break;
            }
        }

        break;
    case MQTT_EVENT_ERROR:

        if (event->error_handle->error_type == MQTT_ERROR_TYPE_TCP_TRANSPORT)
        {
            ESP_LOGI(TAG, "Last errno string (%s)", strerror(event->error_handle->esp_transport_sock_errno));
        }
        break;
    default:
        ESP_LOGI(TAG, "Other event id:%d", event->event_id);
        break;
    }
}
bool IPv4_verify(char *ip)
{
    int a, b, c, d;
    int t;
    char i = sscanf(ip, "%d.%d.%d.%d:%d", &a, &b, &c, &d, &t);
    if (5 == i)
    {
        if (0 <= a && a <= 255 && 0 <= b && b <= 255 && 0 <= c && c <= 255 && 0 <= d && d <= 255)
        {
            return true;
        }
    }

    return false;
}
char ip_host[30];
static void mqtt_app_start(void)
{

    if (strlen(mqtt_address) != 0)
    {
        if (IPv4_verify(mqtt_address))
        {
            /* code */
            int a, b, c, d;
            int t;
            sscanf(mqtt_address, "%d.%d.%d.%d:%d", &a, &b, &c, &d, &t);
            sprintf(ip_host, "%d.%d.%d.%d", a, b, c, d);

            esp_mqtt_client_config_t mqtt_cfg = {
                .host = ip_host,
                .port = t,
                .username = mqtt_admin,
                .password = mqtt_password,
            };

            client1 = esp_mqtt_client_init(&mqtt_cfg);
            /* The last argument may be used to pass data to the event handler, in this example mqtt_event_handler */
            esp_mqtt_client_register_event(client1, ESP_EVENT_ANY_ID, mqtt_event_handler, NULL);
            esp_mqtt_client_start(client1);
        }
        else
        {

            esp_mqtt_client_config_t mqtt_cfg = {
                .uri = mqtt_address,
                .username = mqtt_admin,
                .password = mqtt_password,
            };
            client1 = esp_mqtt_client_init(&mqtt_cfg);
            /* The last argument may be used to pass data to the event handler, in this example mqtt_event_handler */
            esp_mqtt_client_register_event(client1, ESP_EVENT_ANY_ID, mqtt_event_handler, NULL);
            esp_mqtt_client_start(client1);
        }
    }
}

static const adc_channel_t channe1 = ADC_CHANNEL_8; // GPIO9
static const adc_atten_t atten1 = ADC_ATTEN_DB_0;

static const adc_channel_t channe2 = ADC_CHANNEL_9; // GPIO10
static const adc_atten_t atten2 = ADC_ATTEN_DB_0;

static esp_adc_cal_characteristics_t adc_chars1;
static esp_adc_cal_characteristics_t adc_chars2;

#define NO_OF_SAMPLES 100 // Multisampling

// ADC Calibration
#if CONFIG_IDF_TARGET_ESP32
#define ADC_EXAMPLE_CALI_SCHEME ESP_ADC_CAL_VAL_EFUSE_VREF
#elif CONFIG_IDF_TARGET_ESP32S2
#define ADC_EXAMPLE_CALI_SCHEME ESP_ADC_CAL_VAL_EFUSE_TP
#elif CONFIG_IDF_TARGET_ESP32C3
#define ADC_EXAMPLE_CALI_SCHEME ESP_ADC_CAL_VAL_EFUSE_TP
#elif CONFIG_IDF_TARGET_ESP32S3
#define ADC_EXAMPLE_CALI_SCHEME ESP_ADC_CAL_VAL_EFUSE_TP_FIT
#endif

const int ntcData[] = {
    329500, //-50
    310900,
    293500,
    277200,
    262000,
    247700,
    234300,
    221700,
    209900,
    198900,
    188500,
    178500,
    169000,
    160200,
    151900,
    144100,
    136700,
    129800,
    123300,
    117100,
    111300,
    105700,
    100500,
    95520,
    90840,
    86430,
    82260,
    78330,
    74610,
    71100,
    67770,
    64570,
    61540,
    58680,
    55970,
    53410,
    50980,
    48680,
    46500,
    44430,
    42470,
    40570,
    38770,
    37060,
    35440,
    33900,
    32440,
    31050,
    29730,
    28480,
    27280,
    26130,
    25030,
    23990,
    23000,
    22050,
    21150,
    20300,
    19480,
    18700,
    17960,
    17240,
    16560,
    15900,
    15280,
    14690,
    14120,
    13580,
    13060,
    12560,
    12090,
    11630,
    11200,
    10780,
    10380,
    10000,
    9632,
    9281,
    8944,
    8622,
    8313,
    8014,
    7728,
    7454,
    7192,
    6940,
    6699,
    6467,
    6245,
    6032,
    5827,
    5629,
    5438,
    5255,
    5080,
    4911,
    4749,
    4593,
    4443,
    4299,
    4160,
    4026,
    3896,
    3771,
    3651,
    3536,
    3425,
    3318,
    3215,
    3116,
    3020,
    2927,
    2838,
    2751,
    2668,
    2588,
    2511,
    2436,
    2364,
    2295,
    2228,
    2163,
    2100,
    2039,
    1980,
    1924,
    1869,
    1816,
    1765,
    1716,
    1668,
    1622,
    1577,
    1533,
    1492,
    1451,
    1412,
    1373,
    1336,
    1301,
    1266,
    1232,
    1200,
    1168,
    1137,
    1108,
    1079,
    1051,
    1024,
    998,
    973,
    948,
    924,
    901,
    878,
    857,
    836,
    815,
    795,
    776,
    757, // 110
};
int NtcGetTemp(int R)
{
    int i;
    int tp;

    for (i = 0; i < 161; i++)
    {
        if (R > ntcData[i])
        {
            break;
        }
    }
    if (i == 0)
    {
        tp = -500; //最低温度
    }
    else if (i >= 161)
    {
        tp = 1100; //最高温度
    }
    else
    {
        tp = (R - ntcData[i - 1]) * 10 / (ntcData[i] - ntcData[i - 1]) + (i - 50 - 1) * 10;
    }
    return tp;
}
static bool adc_calibration_init(void)
{
    esp_err_t ret;
    bool cali_enable = false;

    ret = esp_adc_cal_check_efuse(ADC_EXAMPLE_CALI_SCHEME);
    if (ret == ESP_ERR_NOT_SUPPORTED)
    {
        ESP_LOGW("ADC", "Calibration scheme not supported, skip software calibration");
    }
    else if (ret == ESP_ERR_INVALID_VERSION)
    {
        ESP_LOGW("ADC", "eFuse not burnt, skip software calibration");
    }
    else if (ret == ESP_OK)
    {
        cali_enable = true;
        esp_adc_cal_characterize(ADC_UNIT_1, atten1, ADC_WIDTH_BIT_13, 0, &adc_chars1);
        esp_adc_cal_characterize(ADC_UNIT_1, atten2, ADC_WIDTH_BIT_13, 0, &adc_chars2);
    }
    else
    {
        ESP_LOGE(TAG, "Invalid arg");
    }

    return cali_enable;
}
void vTask_ADC()
{

    bool cali_enable = adc_calibration_init();

    adc1_config_width(ADC_WIDTH_BIT_13);
    adc1_config_channel_atten(channe1, atten1);
    adc1_config_channel_atten(channe2, atten2);

    uint32_t adc_reading1 = 0;
    uint32_t adc_reading2 = 0;

    uint32_t voltage1 = 0;
    uint32_t voltage2 = 0;
    while (1)
    {
        for (int i = 0; i < NO_OF_SAMPLES; i++)
        {
            adc_reading1 += adc1_get_raw(channe1);
            adc_reading2 += adc1_get_raw(channe2);
        }
        adc_reading1 /= NO_OF_SAMPLES;
        adc_reading2 /= NO_OF_SAMPLES;
        if (cali_enable)
        {
            voltage1 = esp_adc_cal_raw_to_voltage(adc_reading1, &adc_chars1);
            voltage2 = esp_adc_cal_raw_to_voltage(adc_reading2, &adc_chars2);
            int R1 = 1200 * 20000 / voltage1 - 30000;
            int R2 = 1200 * 20000 / voltage2 - 30000;
            temp_sim = NtcGetTemp(R1) + temp_sim_Bias;
            temp_probe = NtcGetTemp(R2) + temp_probe_Bias;

            // printf("R1值%d\n温度值%d\n",R1, NtcGetTemp(R1));

            // printf("R2值%d\n温度值%d\n",R2, NtcGetTemp(R2));
        }

        vTaskDelay(pdMS_TO_TICKS(1000));
    }
}
int PCNT_power[4];
#define PCNT_power_time 60
#define PCNT_power_delay PCNT_power_time * 1000
/* Decode what PCNT's unit originated an interrupt
 * and pass this information together with the event type
 * the main program using a queue.
 */
static void clear_PCNT(int unit)
{

    pcnt_counter_clear(unit);
    pcnt_counter_resume(unit);
    PCNT_power[unit] = 0;
}

static void IRAM_ATTR pcnt_example_intr_handler(void *arg)
{
    int pcnt_unit = (int)arg;
    PCNT_power[pcnt_unit]++;
}
/* Initialize PCNT functions:
 *  - configure and initialize PCNT
 *  - set up the input filter
 *  - set up the counter events to watch
 */
bool ISR_service_already_installed = false;
static void pcnt_example_init(int unit, int gpio)
{

    /* Prepare configuration for the PCNT unit */
    pcnt_config_t pcnt_config = {
        // Set PCNT input signal and control GPIOs
        .pulse_gpio_num = gpio,
        .ctrl_gpio_num = -1,
        .unit = unit,
        .channel = PCNT_CHANNEL_1,

        // What to do on the positive / negative edge of pulse input?
        .pos_mode = PCNT_COUNT_INC, // Count up on the positive edge
        .neg_mode = PCNT_COUNT_DIS, // Keep the counter value on the negative edge

        // What to do when control input is low or high?

        .lctrl_mode = PCNT_MODE_KEEP, // Reverse counting direction if low
        .hctrl_mode = PCNT_MODE_KEEP, // Keep the primary counter mode if high
        // Set the maximum and minimum limit values to watch
        .counter_h_lim = 30000,
        .counter_l_lim = 0,
    };

    /* Initialize PCNT unit */
    pcnt_unit_config(&pcnt_config);

    /* Configure and enable the input filte过滤 */
    pcnt_set_filter_value(unit, 10);
    pcnt_filter_enable(unit);

    /* Enable events on zero, maximum and minimum limit values */
    // pcnt_event_enable(unit, PCNT_EVT_ZERO);
    pcnt_event_enable(unit, PCNT_EVT_H_LIM);
    // pcnt_event_enable(unit, PCNT_EVT_L_LIM);

    /* Initialize PCNT's counter */
    pcnt_counter_pause(unit);
    pcnt_counter_clear(unit);
    if (ISR_service_already_installed == false)
    {
        pcnt_isr_service_install(0);
        ISR_service_already_installed = true;
    }

    pcnt_isr_handler_add(unit, pcnt_example_intr_handler, (void *)unit);
    /* Everything is set up, now go to counting */
    pcnt_counter_resume(unit);
}
double Compressor_power = -1;
double Compressor_current = -1;

double Evaporator_fan_power = -1;
double Evaporator_fan_current = -1;

double Condenser_fan_power = -1;
double Condenser_fan_current = -1;

double Voltage = -1;
void vTask_PCNT()
{

    pcnt_example_init(0, 13); //电压
    pcnt_example_init(1, 45); //功率
    // pcnt_example_init(1, 34); //电流
    pcnt_example_init(2, 33);

    pcnt_example_init(3, 14);

    while (1)
    {
        int16_t count = 0;

        vTaskDelay(PCNT_power_delay / portTICK_RATE_MS);
        pcnt_counter_pause(0);
        pcnt_counter_pause(1);
        pcnt_counter_pause(2);
        pcnt_counter_pause(3);

        pcnt_get_counter_value(0, &count);
        if (count == 30000)
        {
            count = 0;
            /* code */
        }
        Voltage = PCNT_power[0] * 30000 + count;

        pcnt_get_counter_value(1, &count);
        if (count == 30000)
        {
            count = 0;
            /* code */
        }
        Compressor_power = PCNT_power[1] * 30000 + count;

        pcnt_get_counter_value(2, &count);
        if (count == 30000)
        {
            count = 0;
            /* code */
        }
        Evaporator_fan_power = PCNT_power[2] * 30000 + count;

        pcnt_get_counter_value(3, &count);
        if (count == 30000)
        {
            count = 0;
            /* code */
        }
        Condenser_fan_power = PCNT_power[3] * 30000 + count;

        Voltage = (Voltage * 1.218) / 15397 * 4001 / PCNT_power_time / 319 * 223;

        Compressor_power = (Compressor_power * 121.8 * 1.218) / 1721506 * 4001 / PCNT_power_time; // 100:/(20/2000)200050/50
        Evaporator_fan_power = (Evaporator_fan_power * 121.8 * 1.218) / 1721506 * 4001 / PCNT_power_time;
        Condenser_fan_power = (Condenser_fan_power * 121.8 * 1.218) / 1721506 * 4001 / PCNT_power_time;

        Compressor_current = Compressor_power / Voltage;
        Evaporator_fan_current = Evaporator_fan_power / Voltage;
        Condenser_fan_current = Condenser_fan_power / Voltage;

        clear_PCNT(0);
        clear_PCNT(1);
        clear_PCNT(2);
        clear_PCNT(3);
    }
}

void MQTT_publish_str(cJSON *response)
{
    uint8_t mac[6];
    char *mac_str = malloc(100);
    esp_wifi_get_mac(WIFI_IF_STA, mac);

    sprintf(mac_str, MACSTR, MAC2STR(mac));
    cJSON_AddStringToObject(response, "MAC", mac_str);
    cJSON_AddStringToObject(response, "Refrigerator_name", Refrigerator_name);
    cJSON_AddStringToObject(response, "Serial_number", Serial_number);
    cJSON_AddStringToObject(response, "refrigerator_username", refrigerator_username);

    cJSON_AddNumberToObject(response, "temp_sim", temp_sim);
    cJSON_AddNumberToObject(response, "temp_probe", temp_probe);
    // cJSON_AddNumberToObject(response, "temp_box", temp_box);
    // cJSON_AddNumberToObject(response, "temp_evaporator", temp_evaporator);

    if ((Upper_temp_limit < temp_sim) && Delay_alarm)
    {
        cJSON_AddBoolToObject(response, "HIAL", true);
        cJSON_AddNumberToObject(response, "HIAL_code", temp_sim - Upper_temp_limit);
    }
    if ((Lower_temp_limit > temp_sim) && Delay_alarm)
    {
        cJSON_AddBoolToObject(response, "loal", true);
        cJSON_AddNumberToObject(response, "loal_code", Lower_temp_limit - temp_sim);
    }
    // cJSON_AddNumberToObject(response, "temp_evaporator", Upper_temp_limit-temp_sim);
    // cJSON_AddNumberToObject(response, "temp_evaporator", temp_evaporator);
    // cJSON_AddNumberToObject(response, "temp_evaporator", temp_evaporator);
    // cJSON_AddNumberToObject(response, "temp_evaporator", temp_evaporator);

    cJSON_AddBoolToObject(response, "device_485_online", device_485_online);
    cJSON_AddBoolToObject(response, "device_485_compressor", device_485_compressor);
    cJSON_AddBoolToObject(response, "device_485_condenser", device_485_condenser);
    cJSON_AddBoolToObject(response, "device_485_evaporator", device_485_evaporator);

    cJSON_AddNumberToObject(response, "Total_power", Compressor_power + Evaporator_fan_power + Condenser_fan_power);
    cJSON_AddNumberToObject(response, "Compressor_power", Compressor_power);
    cJSON_AddNumberToObject(response, "Compressor_current", Compressor_current);
    cJSON_AddNumberToObject(response, "Evaporator_fan_power", Evaporator_fan_power);
    cJSON_AddNumberToObject(response, "Evaporator_fan_current", Evaporator_fan_current);
    cJSON_AddNumberToObject(response, "Condenser_fan_power", Condenser_fan_power);
    cJSON_AddNumberToObject(response, "Condenser_fan_current", Condenser_fan_current);

    cJSON_AddNumberToObject(response, "Voltage", Voltage);
    cJSON_AddNumberToObject(response, "current", Condenser_fan_current + Evaporator_fan_current + Compressor_current);

    cJSON_AddNumberToObject(response, "temp_set", temp_set);                                         //温度设置值
    cJSON_AddNumberToObject(response, "Control_return", Control_return);                             //控制回差
    cJSON_AddNumberToObject(response, "compressor_min_start_time", compressor_min_start_time);       //压缩机启动最小间隔时间
    cJSON_AddNumberToObject(response, "compressor_min_interval_time", compressor_min_interval_time); //压缩机首次启动最小间隔时间
    cJSON_AddNumberToObject(response, "Cabinet_temp_check", Cabinet_temp_check);                     //柜温校正
    cJSON_AddNumberToObject(response, "temp_Lower_limit", temp_Lower_limit);                         //温度设置下限
    cJSON_AddNumberToObject(response, "temp_Lower_Upper", temp_Lower_Upper);                         //温度设置上限
    cJSON_AddNumberToObject(response, "evaporator_temp_check", evaporator_temp_check);               //蒸发器传感器温度校正
    cJSON_AddNumberToObject(response, "Defrosting_cycle", Defrosting_cycle);                         //除霜周期
    cJSON_AddNumberToObject(response, "Defrosting_max_time", Defrosting_max_time);                   //除霜最长时间
    cJSON_AddNumberToObject(response, "Defrosting_end_temp", Defrosting_end_temp);                   //除霜终止温度
    cJSON_AddNumberToObject(response, "Defrosting_drip_time", Defrosting_drip_time);                 //除霜后滴水时间
    cJSON_AddNumberToObject(response, "Defrosting_start_Fan_delay", Defrosting_start_Fan_delay);     //除霜后风机启动延时

    cJSON_AddNumberToObject(response, "Fahrenheit_Celsius", Fahrenheit_Celsius);             //华氏和摄氏选择
    cJSON_AddNumberToObject(response, "temp_cabinet_lower_limit", temp_cabinet_lower_limit); //柜温下限
    cJSON_AddNumberToObject(response, "temp_cabinet_upper_limit", temp_cabinet_upper_limit); //柜温上限
    cJSON_AddNumberToObject(response, "temp_box", temp_box);                                 //箱内温度
    cJSON_AddNumberToObject(response, "temp_evaporator", temp_evaporator);                   //蒸发器温度

    cJSON_AddBoolToObject(response, "defrost_drip_state", defrost_drip_state);
    cJSON_AddBoolToObject(response, "Fan_state", Fan_state);
    cJSON_AddBoolToObject(response, "defrost_state", defrost_state);
    cJSON_AddBoolToObject(response, "compressor_state", compressor_state);
    cJSON_AddBoolToObject(response, "cabinet_min_temp_warning", cabinet_min_temp_warning);
    cJSON_AddBoolToObject(response, "cabinet_max_temp_warning", cabinet_max_temp_warning);
    cJSON_AddBoolToObject(response, "Evaporation_sensor_fault", Evaporation_sensor_fault);
    cJSON_AddBoolToObject(response, "cabinet_sensor_fault", cabinet_sensor_fault);

    cJSON_AddStringToObject(response, "mqtt_subscription", mqtt_subscription);
    free(mac_str);
    return;
}

#define GPIO_OUTPUT_IO_0 18
#define GPIO_OUTPUT_IO_1 19
#define GPIO_OUTPUT_PIN_SEL ((1ULL << GPIO_OUTPUT_IO_0) | (1ULL << GPIO_OUTPUT_IO_1))
void vTask()
{
    // zero-initialize the config structure.
    gpio_config_t io_conf = {};
    // disable interrupt
    io_conf.intr_type = GPIO_INTR_DISABLE;
    // set as output mode
    io_conf.mode = GPIO_MODE_OUTPUT;
    // bit mask of the pins that you want to set,e.g.GPIO18/19
    io_conf.pin_bit_mask = GPIO_OUTPUT_PIN_SEL;
    // disable pull-down mode
    io_conf.pull_down_en = GPIO_PULLDOWN_ENABLE;
    // disable pull-up mode
    io_conf.pull_up_en = 0;
    // configure GPIO with the given settings
    gpio_config(&io_conf);

    while (1)
    {
        vTaskDelay(60 * 1000 / portTICK_RATE_MS);
        if (strlen(mqtt_publish) != 0)
        {
            cJSON *response = cJSON_CreateObject();

            MQTT_publish_str(response);
            char *p = cJSON_Print(response);

            esp_mqtt_client_publish(client1, mqtt_publish, p, 0, 1, 0);
            // printf("vTask finished_arg  %s\n", MQTT_publish_str(response));
            cJSON_Delete(response);
            free(p);
            if ((Upper_temp_limit < temp_sim) && Delay_alarm)
            {
                gpio_set_level(GPIO_OUTPUT_IO_0, 1);
            }
            else
            {
                gpio_set_level(GPIO_OUTPUT_IO_0, 0);
            }

            if ((Upper_temp_limit > temp_sim) && Delay_alarm)
            {
                gpio_set_level(GPIO_OUTPUT_IO_1, 1);
            }
            else
            {
                gpio_set_level(GPIO_OUTPUT_IO_1, 0);
            }
        }
        if (Delay_alarm_time == -1)
        {
        }
        else if (Delay_alarm_time > 0)
        {
            Delay_alarm_time--;
            printf("Delay_alarm_time = %d\n", Delay_alarm_time);
        }
        else if (Delay_alarm_time == 0)
        {
            Delay_alarm_time--;
            printf("Delay_alarm_time = %d\n", Delay_alarm_time);
            Delay_alarm = true;
        }
    }
}

#define BUF_SIZE (200)
#define BAUD_RATE 9600

#define ECHO_TEST_TXD (36)
#define ECHO_TEST_RXD (38)

// RTS for RS485 Half-Duplex Mode manages DE/~RE
#define ECHO_TEST_RTS (37)

// CTS is not used in RS485 Half-Duplex Mode
#define ECHO_TEST_CTS (UART_PIN_NO_CHANGE)

#define ECHO_READ_TOUT (3) // 3.5T * 8 = 28 ticks, TOUT=3 -> ~24..33 ticks
#define PACKET_READ_TICS (1000 / portTICK_RATE_MS)

static void echo_send(const int port, const char *str, uint8_t length)
{
    if (uart_write_bytes(port, str, length) != length)
    {
        ESP_LOGE(TAG, "Send data critical failure.");
        // add your code to handle sending failure here
        abort();
    }
}
unsigned char CRC8_Tab(unsigned char ky)
{
    unsigned char ki;
    for (ki = 0; ki < 8; ki++)
    {
        if (ky & 0x80)
        {
            ky *= 2;
            ky ^= 0x31;
        }
        else
        {
            ky *= 2;
        }
    }
    return ky;
}
unsigned char CRC8_Tabb(unsigned char ky)
{
    unsigned char ki;
    for (ki = 0; ki < 8; ki++)
    {
        if (ky & 0x80)
        {
            ky *= 2;
            ky ^= 0x31;
        }
        else
        {
            ky *= 2;
        }
    }
    return ky;
}
unsigned char Get_CRC_Result(u_char *kcr, int len)
{
    unsigned char gt1, gt2;
    gt2 = 0;
    for (gt1 = 0; gt1 < len; gt1++)
    {
        gt2 = CRC8_Tabb((*kcr) ^ gt2);
        kcr++;
    }
    return gt2;
}

/* Table of CRC values for high–order byte */
const unsigned char auchCRCHi[] = {
    0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81,
    0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0,
    0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01,
    0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41,
    0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81,
    0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0,
    0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01,
    0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40,
    0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81,
    0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0,
    0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01,
    0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,
    0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81,
    0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0,
    0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01,
    0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,
    0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81,
    0x40};

/* Table of CRC values for low–order byte */
const unsigned char auchCRCLo[] = {
    0x00, 0xC0, 0xC1, 0x01, 0xC3, 0x03, 0x02, 0xC2, 0xC6, 0x06, 0x07, 0xC7, 0x05, 0xC5, 0xC4,
    0x04, 0xCC, 0x0C, 0x0D, 0xCD, 0x0F, 0xCF, 0xCE, 0x0E, 0x0A, 0xCA, 0xCB, 0x0B, 0xC9, 0x09,
    0x08, 0xC8, 0xD8, 0x18, 0x19, 0xD9, 0x1B, 0xDB, 0xDA, 0x1A, 0x1E, 0xDE, 0xDF, 0x1F, 0xDD,
    0x1D, 0x1C, 0xDC, 0x14, 0xD4, 0xD5, 0x15, 0xD7, 0x17, 0x16, 0xD6, 0xD2, 0x12, 0x13, 0xD3,
    0x11, 0xD1, 0xD0, 0x10, 0xF0, 0x30, 0x31, 0xF1, 0x33, 0xF3, 0xF2, 0x32, 0x36, 0xF6, 0xF7,
    0x37, 0xF5, 0x35, 0x34, 0xF4, 0x3C, 0xFC, 0xFD, 0x3D, 0xFF, 0x3F, 0x3E, 0xFE, 0xFA, 0x3A,
    0x3B, 0xFB, 0x39, 0xF9, 0xF8, 0x38, 0x28, 0xE8, 0xE9, 0x29, 0xEB, 0x2B, 0x2A, 0xEA, 0xEE,
    0x2E, 0x2F, 0xEF, 0x2D, 0xED, 0xEC, 0x2C, 0xE4, 0x24, 0x25, 0xE5, 0x27, 0xE7, 0xE6, 0x26,
    0x22, 0xE2, 0xE3, 0x23, 0xE1, 0x21, 0x20, 0xE0, 0xA0, 0x60, 0x61, 0xA1, 0x63, 0xA3, 0xA2,
    0x62, 0x66, 0xA6, 0xA7, 0x67, 0xA5, 0x65, 0x64, 0xA4, 0x6C, 0xAC, 0xAD, 0x6D, 0xAF, 0x6F,
    0x6E, 0xAE, 0xAA, 0x6A, 0x6B, 0xAB, 0x69, 0xA9, 0xA8, 0x68, 0x78, 0xB8, 0xB9, 0x79, 0xBB,
    0x7B, 0x7A, 0xBA, 0xBE, 0x7E, 0x7F, 0xBF, 0x7D, 0xBD, 0xBC, 0x7C, 0xB4, 0x74, 0x75, 0xB5,
    0x77, 0xB7, 0xB6, 0x76, 0x72, 0xB2, 0xB3, 0x73, 0xB1, 0x71, 0x70, 0xB0, 0x50, 0x90, 0x91,
    0x51, 0x93, 0x53, 0x52, 0x92, 0x96, 0x56, 0x57, 0x97, 0x55, 0x95, 0x94, 0x54, 0x9C, 0x5C,
    0x5D, 0x9D, 0x5F, 0x9F, 0x9E, 0x5E, 0x5A, 0x9A, 0x9B, 0x5B, 0x99, 0x59, 0x58, 0x98, 0x88,
    0x48, 0x49, 0x89, 0x4B, 0x8B, 0x8A, 0x4A, 0x4E, 0x8E, 0x8F, 0x4F, 0x8D, 0x4D, 0x4C, 0x8C,
    0x44, 0x84, 0x85, 0x45, 0x87, 0x47, 0x46, 0x86, 0x82, 0x42, 0x43, 0x83, 0x41, 0x81, 0x80,
    0x40};

unsigned short ModBusCRC16(unsigned char *puchMsg, unsigned short usDataLen)
{
    unsigned char uchCRCHi = 0xFF; /* high byte of CRC initialized */
    unsigned char uchCRCLo = 0xFF; /* low byte of CRC initialized */
    unsigned uIndex;               /* will index into CRC lookup table */
    while (usDataLen--)            /* pass through message buffer */
    {
        uIndex = uchCRCHi ^ *puchMsg++; /* calculate the CRC */
        uchCRCHi = uchCRCLo ^ auchCRCHi[uIndex];
        uchCRCLo = auchCRCLo[uIndex];
    }
    return (uchCRCHi << 8 | uchCRCLo);
}

int16_t Modbus_read(int16_t address)
{
    unsigned char data[BUF_SIZE];
    data[0] = 0x01;
    data[1] = 0x46;
    data[2] = address >> 8;
    data[3] = address % 256;
    data[4] = 0x00;
    data[5] = 0x01;
    int crc16 = ModBusCRC16(data, 6);
    data[6] = crc16 >> 8;
    data[7] = crc16 % 256;

    echo_send(UART_NUM_1, (char *)data, 8);

    int len = uart_read_bytes(UART_NUM_1, data, BUF_SIZE, PACKET_READ_TICS);
    if (len > 0)
    {
        device_485_online = true;
        if (data[len - 2] * 256 + data[len - 1] == ModBusCRC16(data, len - 2))
        {

            if (data[0] == 0x01)
            {

                if (data[1] == 0x46)
                {

                    return (data[4] << 8) + data[5];
                }
            }
        }
    }
    else
    {
        device_485_online = false;
    }
    return 0;
}
bool Modbus_write(int16_t address, int16_t data1)
{
    unsigned char data[BUF_SIZE];
    data[0] = 0x01;
    data[1] = 0x47;
    data[2] = address >> 8;
    data[3] = address % 256;
    data[4] = data1 >> 8;
    data[5] = data1 % 256;
    int crc16 = ModBusCRC16(data, 6);
    data[6] = crc16 >> 8;
    data[7] = crc16 % 256;

    echo_send(UART_NUM_1, (char *)data, 8);

    int len = uart_read_bytes(UART_NUM_1, data, BUF_SIZE, PACKET_READ_TICS);
    if (len > 0)
    {
        device_485_online = true;
        if (data[len - 2] * 256 + data[len - 1] == ModBusCRC16(data, len - 2))
        {
            if (data[0] == 0x01)
            {
                if (data[1] == 0x47)
                {
                    return 1;
                }
            }
        }
    }
    else
    {
        device_485_online = false;
    }
    return 0;
}

void vTask_uart_485()
{
    const int uart_num = UART_NUM_1;
    uart_config_t uart_config = {
        .baud_rate = BAUD_RATE,
        .data_bits = UART_DATA_8_BITS,
        .parity = UART_PARITY_DISABLE,
        .stop_bits = UART_STOP_BITS_1,
        .flow_ctrl = UART_HW_FLOWCTRL_DISABLE,
        .rx_flow_ctrl_thresh = 122,
        .source_clk = UART_SCLK_APB,
    };

    // Set UART log level
    esp_log_level_set(TAG, ESP_LOG_INFO);

    ESP_ERROR_CHECK(uart_driver_install(uart_num, BUF_SIZE, BUF_SIZE, 2, NULL, 0));

    // Configure UART parameters
    ESP_ERROR_CHECK(uart_param_config(uart_num, &uart_config));

    ESP_ERROR_CHECK(uart_set_pin(uart_num, ECHO_TEST_TXD, ECHO_TEST_RXD, ECHO_TEST_RTS, ECHO_TEST_CTS));

    ESP_ERROR_CHECK(uart_set_mode(uart_num, UART_MODE_RS485_HALF_DUPLEX));

    ESP_ERROR_CHECK(uart_set_rx_timeout(uart_num, ECHO_READ_TOUT));

    unsigned char data[BUF_SIZE];
    // echo_send(uart_num, "Start RS485 UART test.\r\n", 24);
    while (1)
    {

        if (protocol_485 == 0)
        {

            data[0] = 0xcc;
            data[1] = 0x76;
            data[2] = 0x00;
            data[3] = 0x01;
            data[4] = 0x01;
            data[5] = 0x00;
            data[6] = 0xdd;
            data[7] = 0xee;
            data[8] = Get_CRC_Result(data, 8);
            echo_send(uart_num, (char *)data, 9);

            int len = uart_read_bytes(uart_num, data, BUF_SIZE, PACKET_READ_TICS);
            if (len > 0)
            {
                device_485_online = true;
                if (data[len - 1] == Get_CRC_Result(data, len - 1))
                {
                    temp_box = data[6] * 10 + data[7];
                }
            }
            else
            {
                device_485_online = false;
            }

            data[0] = 0xcc;
            data[1] = 0x76;
            data[2] = 0x00;
            data[3] = 0x02;
            data[4] = 0x01;
            data[5] = 0x00;
            data[6] = 0xdd;
            data[7] = 0xee;
            data[8] = Get_CRC_Result(data, 8);
            echo_send(uart_num, (char *)data, 9);

            len = uart_read_bytes(uart_num, data, BUF_SIZE, PACKET_READ_TICS);
            if (len > 0)
            {
                device_485_online = true;
                if (data[len - 1] == Get_CRC_Result(data, len - 1))
                {
                    temp_evaporator = data[5] * 10 + data[6];
                }
            }
            else
            {
                device_485_online = false;
            }
            data[0] = 0xcc;
            data[1] = 0x76;
            data[2] = 0x00;
            data[3] = 0x03;
            data[4] = 0x01;
            data[5] = 0x00;
            data[6] = 0xdd;
            data[7] = 0xee;
            data[8] = Get_CRC_Result(data, 8);
            echo_send(uart_num, (char *)data, 9);

            len = uart_read_bytes(uart_num, data, BUF_SIZE, PACKET_READ_TICS);
            if (len > 0)
            {
                device_485_online = true;
                if (data[len - 1] == Get_CRC_Result(data, len - 1))
                {
                    device_485_compressor = ((data[5] & 0x40) == 0x40);
                    device_485_condenser = ((data[5] & 0x20) == 0x20);
                    device_485_evaporator = ((data[5] & 0x10) == 0x10);
                }
            }
            else
            {
                device_485_online = false;
            }
        }
        else if (protocol_485 == 1)
        {

            temp_set = Modbus_read(0x0100); //温度设置值

            Control_return = Modbus_read(0x0102);               //控制回差
            compressor_min_start_time = Modbus_read(0x0103);    //压缩机启动最小间隔时间
            compressor_min_interval_time = Modbus_read(0x0104); //压缩机首次启动最小间隔时间
            Cabinet_temp_check = Modbus_read(0x0105);           //柜温校正
            temp_Lower_limit = Modbus_read(0x0106);             //温度设置下限
            temp_Lower_Upper = Modbus_read(0x0107);             //温度设置上限
            evaporator_temp_check = Modbus_read(0x010a);        //蒸发器传感器温度校正
            Defrosting_cycle = Modbus_read(0x010b);             //除霜周期
            Defrosting_max_time = Modbus_read(0x010c);          //除霜最长时间
            Defrosting_end_temp = Modbus_read(0x010d);          //除霜终止温度
            Defrosting_drip_time = Modbus_read(0x010e);         //除霜后滴水时间
            Defrosting_start_Fan_delay = Modbus_read(0x0112);   //除霜后风机启动延时
            Fahrenheit_Celsius = Modbus_read(0x040d);           //华氏和摄氏选择
            temp_cabinet_lower_limit = Modbus_read(0x0117);     //柜温下限
            temp_cabinet_upper_limit = Modbus_read(0x0118);     //柜温上限
            temp_box = Modbus_read(0x0124);                     //箱内温度
            temp_evaporator = Modbus_read(0x0125);              //蒸发器温度

            int temp = Modbus_read(0x0200);

            defrost_drip_state = ((temp & 0x2000) == 0x2000); //化霜滴水状态
            Fan_state = ((temp & 0x0400) == 0x0400);          //风机状态
            defrost_state = ((temp & 0x0200) == 0x0200);      //化霜状态
            compressor_state = ((temp & 0x0100) == 0x0100);   //压缩机状态
            temp = Modbus_read(0x0300);
            cabinet_min_temp_warning = ((temp & 0x0010) == 0x0010); //柜温低温报警
            cabinet_max_temp_warning = ((temp & 0x0008) == 0x0008); //柜温高温报警
            Evaporation_sensor_fault = ((temp & 0x0002) == 0x0002); //蒸发传感器故障
            cabinet_sensor_fault = ((temp & 0x0001) == 0x0001);     //柜温传感器故障
        }
        else
        {
        }
        vTaskDelay(1000 / portTICK_PERIOD_MS);
        // int len = uart_read_bytes(uart_num, data, BUF_SIZE, PACKET_READ_TICS);
        // if (len > 0)
        // {

        //     char prefix[] = "RS485 Received: [";
        //     echo_send(uart_num, prefix, (sizeof(prefix) - 1));
        //     echo_send(uart_num, (char*)data, len);
        //     echo_send(uart_num, "]\r\n", 3);
        //     // printf("vTask_GPIO\r\n");
        // }
    }
}
void state_task()
{
    static char InfoBuffer[512] = {0};
    while (1)
    {
        vTaskList((char *)&InfoBuffer);
        printf("任务名      任务状态 优先级   剩余栈 任务序号\r\n");
        printf("\r\n%s\r\n", InfoBuffer);
        vTaskDelay(10000 / portTICK_PERIOD_MS);
    }
}

#define GPIO_INPUT_IO_0 0
#define GPIO_INPUT_PIN_SEL ((1ULL << GPIO_INPUT_IO_0))
void vTask_reset()
{
    gpio_config_t io_conf = {};
    // interrupt of rising edge
    io_conf.intr_type = GPIO_INTR_POSEDGE;
    // bit mask of the pins, use GPIO4/5 here
    io_conf.pin_bit_mask = GPIO_INPUT_PIN_SEL;
    // set as input mode
    io_conf.mode = GPIO_MODE_INPUT;
    // enable pull-up mode
    io_conf.pull_up_en = 1;
    // disable pull-down mode
    io_conf.pull_down_en = 0;
    // disable pull-up mode
    io_conf.pull_up_en = 1;

    gpio_config(&io_conf);
    while (true)
    {
        if (gpio_get_level(GPIO_INPUT_IO_0) == 0)
        {

            vTaskDelay(5000 / portTICK_PERIOD_MS);

            if (gpio_get_level(GPIO_INPUT_IO_0) == 0)
            {

                esp_err_t err = nvs_flash_init();
                if (err == ESP_ERR_NVS_NO_FREE_PAGES || err == ESP_ERR_NVS_NEW_VERSION_FOUND)
                {
                    // NVS分区被截断，需要擦除并重新初始化
                    ESP_ERROR_CHECK(nvs_flash_erase());
                    err = nvs_flash_init();
                }
                ESP_ERROR_CHECK(err);

                nvs_handle_t my_handle;
                err = nvs_open("storage", NVS_READWRITE, &my_handle);

                nvs_erase_all(my_handle);
                vTaskDelay(100 / portTICK_PERIOD_MS);
                esp_restart();
            }
        }
        else
        {

            vTaskDelay(100 / portTICK_PERIOD_MS);
        }
    }
}

static httpd_handle_t start_webserver(void);

static esp_err_t validate_image_header(esp_app_desc_t *new_app_info)
{
    if (new_app_info == NULL)
    {
        return ESP_ERR_INVALID_ARG;
    }

    const esp_partition_t *running = esp_ota_get_running_partition();
    esp_app_desc_t running_app_info;
    if (esp_ota_get_partition_description(running, &running_app_info) == ESP_OK)
    {
        ESP_LOGI(TAG, "Running firmware version: %s", running_app_info.version);
    }

#ifndef CONFIG_EXAMPLE_SKIP_VERSION_CHECK

    if (memcmp(new_app_info->app_elf_sha256, running_app_info.app_elf_sha256, sizeof(new_app_info->app_elf_sha256)) == 0)
    {
        ESP_LOGW(TAG, "Current running version is the same as a new. We will not continue the update.");
        return ESP_FAIL;
    }
#endif

#ifdef CONFIG_BOOTLOADER_APP_ANTI_ROLLBACK
    /**
     * Secure version check from firmware image header prevents subsequent download and flash write of
     * entire firmware image. However this is optional because it is also taken care in API
     * esp_https_ota_finish at the end of OTA update procedure.
     */
    const uint32_t hw_sec_version = esp_efuse_read_secure_version();
    if (new_app_info->secure_version < hw_sec_version)
    {
        ESP_LOGW(TAG, "New firmware security version is less than eFuse programmed, %d < %d", new_app_info->secure_version, hw_sec_version);
        return ESP_FAIL;
    }
#endif

    return ESP_OK;
}
esp_err_t do_firmware_upgrade()
{

    esp_http_client_config_t config = {
        .url = "http://192.168.1.88:8080/hello_world.bin",
        .timeout_ms = 1000
        //.cert_pem = (char *)server_cert_pem_start,
    };
    // esp_err_t ret = esp_https_ota(&config);

    esp_https_ota_config_t ota_config = {
        .http_config = &config,
    };

    esp_https_ota_handle_t https_ota_handle = NULL;
    esp_err_t err = esp_https_ota_begin(&ota_config, &https_ota_handle);
    if (https_ota_handle == NULL)
    {
        return ESP_FAIL;
    }

    esp_app_desc_t app_desc;
    err = esp_https_ota_get_img_desc(https_ota_handle, &app_desc);
    if (err != ESP_OK)
    {
        ESP_LOGE(TAG, "esp_https_ota_read_img_desc failed");
        esp_https_ota_abort(https_ota_handle);
        ESP_LOGE(TAG, "ESP_HTTPS_OTA upgrade failed");
        return ESP_FAIL;
    }

    err = validate_image_header(&app_desc);
    if (err != ESP_OK)
    {
        ESP_LOGE(TAG, "image header verification failed");
        esp_https_ota_abort(https_ota_handle);
        ESP_LOGE(TAG, "ESP_HTTPS_OTA upgrade failed");
        return ESP_OK;
    }

    while (1)
    {
        err = esp_https_ota_perform(https_ota_handle);
        if (err != ESP_ERR_HTTPS_OTA_IN_PROGRESS)
        {
            break;
        }
    }

    if (err != ESP_OK)
    {
        esp_https_ota_abort(https_ota_handle);
        return err;
    }

    esp_err_t ota_finish_err = esp_https_ota_finish(https_ota_handle);
    if (ota_finish_err != ESP_OK)
    {
        return ota_finish_err;
    }
    esp_restart();
    return ESP_OK;
}
// #define OTA_time 3*24*60
// void vTask_OTA()
// {
//     while (true)
//     {
//         for ( size_t i = 0; i < OTA_time; i++)
//         {
//            vTaskDelay(60*1000/ portTICK_PERIOD_MS);
//         }
//         do_firmware_upgrade();
//         esp_restart();
//     }

// }
void vTask_OTA()
{
    while (ESP_OK!=do_firmware_upgrade())
    {
        vTaskDelay(1*1000/ portTICK_PERIOD_MS);
    }
    
    
    
    while (true)
    {
        //vTaskDelay(5 * 1000 / portTICK_PERIOD_MS);
        vTaskDelay(3*24*60*60*1000/ portTICK_PERIOD_MS);
      

        do_firmware_upgrade();
    }
}
void app_main(void)
{

    app_nvs_flash_init();
    wifi_init_apsta();
    start_webserver();
    mqtt_app_start();
    xTaskCreatePinnedToCore(vTask_ADC, "vTask_ADC", 4096, NULL, 10, NULL, tskNO_AFFINITY);
    xTaskCreatePinnedToCore(vTask_PCNT, "vTask_PCNT", 4096, NULL, 10, NULL, tskNO_AFFINITY);
    xTaskCreatePinnedToCore(vTask, "vTask", 4096, NULL, 10, NULL, tskNO_AFFINITY);
    xTaskCreatePinnedToCore(vTask_uart_485, "vTask_uart_485", 4096, NULL, 10, NULL, tskNO_AFFINITY);
    xTaskCreatePinnedToCore(vTask_reset, "vTask_reset", 2048, NULL, 10, NULL, tskNO_AFFINITY);
    xTaskCreatePinnedToCore(vTask_OTA, "vTask_OTA", 8000, NULL, 10, NULL, tskNO_AFFINITY);

    // xTaskCreatePinnedToCore(state_task, "state_task", 4096, NULL, 10, NULL, tskNO_AFFINITY);

    // xTaskCreate(vTask_uart_485, "vTask_uart_485", 128, NULL, 4, NULL);

    // while(1);
    // fflush(stdout);
    // esp_restart();
}

#define NON_NUM '0'
char Char2Num(char ch)
{
    if (ch >= '0' && ch <= '9')
        return (char)(ch - '0');
    if (ch >= 'a' && ch <= 'f')
        return (char)(ch - 'a' + 10);
    if (ch >= 'A' && ch <= 'F')
        return (char)(ch - 'A' + 10);
    return NON_NUM;
}

int URLDecode(const char *str, const int strSize, char *result, const int resultSize)
{
    char ch, ch1, ch2;
    int i;
    int j = 0; /* for result index */

    if ((str == NULL) || (result == NULL) || (strSize <= 0) || (resultSize <= 0))
    {
        return 0;
    }

    for (i = 0; (i < strSize) && (j < resultSize)&&(str[i]!='\0'); i++)
    {
        ch = str[i];
        switch (ch)
        {
        case '+':
            result[j++] = ' ';
            break;

        case '%':
            if ((i + 2) < strSize)
            {
                ch1 = Char2Num(str[i + 1]);
                ch2 = Char2Num(str[i + 2]);
                if ((ch1 != NON_NUM) && (ch2 != NON_NUM))
                {
                    result[j++] = (char)((ch1 << 4) | ch2);
                    i += 2;
                    break;
                }
            }
            result[j++] = ch;
            break;

        /* goto default */
        default:
            result[j++] = ch;
            break;
        }
    }

    result[j] = '\0';
    return j;
}

/* An HTTP POST handler */
void http_success(httpd_req_t *req, int code, char *message, cJSON *data)
{
    cJSON *response = cJSON_CreateObject();
    cJSON_AddNumberToObject(response, "code", code);
    cJSON_AddStringToObject(response, "message", message);
    cJSON_AddItemToObject(response, "data", data);
    char *buf = cJSON_Print(response);
    httpd_resp_send_chunk(req, buf, strlen(buf));

    cJSON_Delete(response);
    free(buf);
}
static esp_err_t echo_post_handler(httpd_req_t *req)
{
    char *buf;
    size_t buf_len = 0;
    bool is_en_esp_restart = false;
    buf_len = httpd_req_get_url_query_len(req) + 1;
    if (buf_len > 1)
    {
        buf = malloc(buf_len);
        if (httpd_req_get_url_query_str(req, buf, buf_len) == ESP_OK)
        {
            ESP_LOGI(TAG, "Found URL query => %s", buf);
            char param[384];
            char param1[128];
            /* Get value of expected key from query string */
            if (httpd_query_key_value(buf, "token", param, sizeof(param)) == ESP_OK)
            {
                ESP_LOGI(TAG, "Found URL query parameter => query1=%s", Module_password);
                ESP_LOGI(TAG, "Found URL query parameter => query2=%s", param);
                URLDecode(param, strlen(param), param1, 30);
                if (strcmp(Module_password, param1) == 0)
                {
                    if (httpd_query_key_value(buf, "sta_wifi_name", param, sizeof(param)) == ESP_OK)
                    {
                        if (strlen(param) != 0)
                        {
                            URLDecode(param, strlen(param), sta_wifi_name, 32);
                            //strcpy(sta_wifi_name, param);
                            is_en_esp_restart = true;
                        }
                        else
                        {
                            cJSON *data = cJSON_CreateObject();
                            http_success(req, 200, "sta不能没有名称", data);
                            httpd_resp_send_chunk(req, NULL, 0);

                            free(buf);
                            return ESP_OK;
                        }
                    }
                    if (httpd_query_key_value(buf, "sta_wifi_password", param, sizeof(param)) == ESP_OK)
                    {
                        
                        if ( URLDecode(param, strlen(param), param1, 64)>= 8)
                        {
                            strcpy(sta_wifi_password, param1);
                            is_en_esp_restart = true;
                        }
                        else
                        {
                            if (strlen(param) != 0)
                            {
                                cJSON *data = cJSON_CreateObject();
                                http_success(req, 200, "sta密码不能少于8位", data);
                                httpd_resp_send_chunk(req, NULL, 0);
                                free(buf);

                                return ESP_OK;
                            }
                        }
                    }

                    if (httpd_query_key_value(buf, "ap_wifi_name", param, sizeof(param)) == ESP_OK)
                    {
                        if (strlen(param) != 0)
                        {
                            URLDecode(param, strlen(param), ap_wifi_name, 32);
                        }
                    }
                    if (httpd_query_key_value(buf, "ap_wifi_password", param, sizeof(param)) == ESP_OK)
                    {

                        if (URLDecode(param, strlen(param), param1, 64)>= 8)
                        {
                            strcpy(ap_wifi_password, param1);
                        }
                        else
                        {
                            if (strlen(param) != 0)
                            {
                                cJSON *data = cJSON_CreateObject();
                                http_success(req, 200, "AP密码不能少于8位", data);
                                httpd_resp_send_chunk(req, NULL, 0);
                                free(buf);

                                return ESP_OK;
                            }
                        }
                    }

                    if (httpd_query_key_value(buf, "Refrigerator_name", param, sizeof(param)) == ESP_OK)
                    {

                        URLDecode(param, strlen(param), Refrigerator_name, 40);
                    }
                    if (httpd_query_key_value(buf, "Serial_number", param, sizeof(param)) == ESP_OK)
                    {
                        URLDecode(param, strlen(param), Serial_number, 32);
                        // strcpy(Serial_number, str);
                    }

                    if (httpd_query_key_value(buf, "Upper_temp_limit", param, sizeof(param)) == ESP_OK)
                    {
                        Upper_temp_limit = atoi(param);
                    }

                    if (httpd_query_key_value(buf, "Delay_alarm_time", param, sizeof(param)) == ESP_OK)
                    {
                        Delay_alarm_time = atoi(param);
                    }

                    if (httpd_query_key_value(buf, "Lower_temp_limit", param, sizeof(param)) == ESP_OK)
                    {
                        Lower_temp_limit = atoi(param);
                    }

                    if (httpd_query_key_value(buf, "temp_sim_Bias", param, sizeof(param)) == ESP_OK)
                    {
                        temp_sim_Bias = atoi(param);
                    }

                    if (httpd_query_key_value(buf, "temp_probe_Bias", param, sizeof(param)) == ESP_OK)
                    {
                        temp_probe_Bias = atoi(param);
                    }

                    if (httpd_query_key_value(buf, "protocol_485", param, sizeof(param)) == ESP_OK)
                    {
                        protocol_485 = atoi(param);
                    }

                    if (httpd_query_key_value(buf, "mqtt_address", param, sizeof(param)) == ESP_OK)
                    {
                        URLDecode(param, strlen(param), mqtt_address, 128);
                        //strcpy(mqtt_address, param);
                        is_en_esp_restart = true;
                    }
                    if (httpd_query_key_value(buf, "mqtt_admin", param, sizeof(param)) == ESP_OK)
                    {
                        URLDecode(param, strlen(param), mqtt_admin, 128);
                        //strcpy(mqtt_admin, param);
                        is_en_esp_restart = true;
                    }
                    if (httpd_query_key_value(buf, "mqtt_password", param, sizeof(param)) == ESP_OK)
                    {
                        URLDecode(param, strlen(param), mqtt_password, 128);
                        //strcpy(mqtt_password, param);
                        is_en_esp_restart = true;
                    }
                    if (httpd_query_key_value(buf, "mqtt_subscription", param, sizeof(param)) == ESP_OK)
                    {
                         URLDecode(param, strlen(param), mqtt_subscription, 128);
                        //strcpy(mqtt_subscription, param);
                        is_en_esp_restart = true;
                    }
                    if (httpd_query_key_value(buf, "mqtt_publish", param, sizeof(param)) == ESP_OK)
                    {
                        URLDecode(param, strlen(param), mqtt_publish, 128);
                        //strcpy(mqtt_publish, param);
                        is_en_esp_restart = true;
                    }

                    if (httpd_query_key_value(buf, "temp_cail1", param, sizeof(param)) == ESP_OK)
                    {
                        temp_cail1 = atoi(param);
                    }
                    if (httpd_query_key_value(buf, "temp_cail2", param, sizeof(param)) == ESP_OK)
                    {
                        temp_cail2 = atoi(param);
                    }

                    if (httpd_query_key_value(buf, "refrigerator_username", param, sizeof(param)) == ESP_OK)
                    {
                        URLDecode(param, strlen(param), refrigerator_username, 128);
                        // strcpy(refrigerator_username, str);
                    }
                    if (httpd_query_key_value(buf, "IP_address", param, sizeof(param)) == ESP_OK)
                    {
                       
                        strcpy(IP_address, param);
                        is_en_esp_restart = true;
                    }
                    if (httpd_query_key_value(buf, "DNS_address", param, sizeof(param)) == ESP_OK)
                    {
                        strcpy(DNS_address, param);
                        is_en_esp_restart = true;
                    }
                    if (httpd_query_key_value(buf, "GW_address", param, sizeof(param)) == ESP_OK)
                    {
                        strcpy(GW_address, param);
                        is_en_esp_restart = true;
                    }
                    if (httpd_query_key_value(buf, "Subnet_mask_address", param, sizeof(param)) == ESP_OK)
                    {
                        strcpy(Subnet_mask_address, param);
                        is_en_esp_restart = true;
                    }

                    if (httpd_query_key_value(buf, "En_DHCP", param, sizeof(param)) == ESP_OK)
                    {
                        En_DHCP = atoi(param);
                        is_en_esp_restart = true;
                    }

                    if (httpd_query_key_value(buf, "Module_password", param, sizeof(param)) == ESP_OK)
                    {
                        
                        if (URLDecode(param, 128, param1, 128)>= 6)
                        {
                            
                            strcpy(Module_password, param1);
                        }
                        else
                        {
                            if (strlen(param) != 0)
                            {
                                cJSON *data = cJSON_CreateObject();
                                http_success(req, 200, "密码不能少于6位", data);
                                httpd_resp_send_chunk(req, NULL, 0);
                                free(buf);
                                return ESP_OK;
                            }
                        }
                    }

                    NVS_save();
                    cJSON *data = cJSON_CreateObject();
                    http_success(req, 200, "设置成功", data);
                    httpd_resp_send_chunk(req, NULL, 0);
                    free(buf);
                    if (is_en_esp_restart)
                    {
                        vTaskDelay(1000 / portTICK_PERIOD_MS);
                        esp_restart();
                    }

                    return ESP_OK;
                }
                else
                {
                    cJSON *data = cJSON_CreateObject();
                    http_success(req, 401, "密码错误", data);
                    httpd_resp_send_chunk(req, NULL, 0);
                    free(buf);

                    return ESP_OK;
                }
            }
        }
        free(buf);
    }

    // End response

    cJSON *data = cJSON_CreateObject();
    cJSON_AddNumberToObject(data, "code", 123);
    http_success(req, 200, "OK", data);
    httpd_resp_send_chunk(req, NULL, 0);

    return ESP_OK;
}

static const httpd_uri_t echo = {
    .uri = "/echo",
    .method = HTTP_POST,
    .handler = echo_post_handler,
    .user_ctx = NULL};

static esp_err_t read_get_handler(httpd_req_t *req)
{
    cJSON *data = cJSON_CreateObject();

    cJSON_AddStringToObject(data, "sta_wifi_name", sta_wifi_name);
    cJSON_AddStringToObject(data, "sta_wifi_password", sta_wifi_password);

    cJSON_AddStringToObject(data, "ap_wifi_name", ap_wifi_name);
    cJSON_AddStringToObject(data, "ap_wifi_password", ap_wifi_password);

    cJSON_AddStringToObject(data, "Refrigerator_name", Refrigerator_name);
    cJSON_AddStringToObject(data, "Serial_number", Serial_number);

    cJSON_AddNumberToObject(data, "Upper_temp_limit", Upper_temp_limit);
    cJSON_AddNumberToObject(data, "Lower_temp_limit", Lower_temp_limit);

    cJSON_AddNumberToObject(data, "Delay_alarm_time", Delay_alarm_time);

    cJSON_AddNumberToObject(data, "temp_sim_Bias", temp_sim_Bias);
    cJSON_AddNumberToObject(data, "temp_probe_Bias", temp_probe_Bias);

    cJSON_AddNumberToObject(data, "protocol_485", protocol_485);

    cJSON_AddStringToObject(data, "mqtt_address", mqtt_address);
    cJSON_AddStringToObject(data, "mqtt_admin", mqtt_admin);
    cJSON_AddStringToObject(data, "mqtt_password", mqtt_password);
    cJSON_AddStringToObject(data, "mqtt_subscription", mqtt_subscription);
    cJSON_AddStringToObject(data, "mqtt_publish", mqtt_publish);

    cJSON_AddNumberToObject(data, "temp_cail1", temp_cail1);
    cJSON_AddNumberToObject(data, "temp_cail2", temp_cail2);

    cJSON_AddStringToObject(data, "refrigerator_username", refrigerator_username);

    cJSON_AddStringToObject(data, "IP_address", IP_address);
    cJSON_AddStringToObject(data, "DNS_address", DNS_address);
    cJSON_AddStringToObject(data, "GW_address", GW_address);
    cJSON_AddStringToObject(data, "Subnet_mask_address", Subnet_mask_address);
    cJSON_AddNumberToObject(data, "En_DHCP", En_DHCP);

    // cJSON_AddNumberToObject(data, "code", code);
    // cJSON_AddStringToObject(response, "message", message);
    // cJSON_AddItemToObject(response, "data", data);

    http_success(req, 200, "返回成功", data);

    httpd_resp_send_chunk(req, NULL, 0);

    return ESP_OK;
}
static const httpd_uri_t read_get = {
    .uri = "/read",
    .method = HTTP_GET,
    .handler = read_get_handler,
    .user_ctx = NULL};

static esp_err_t readdata_get_handler(httpd_req_t *req)
{
    cJSON *response = cJSON_CreateObject();
    // MQTT_publish_str(response);
    cJSON_AddNumberToObject(response, "temp_sim", temp_sim);
    cJSON_AddNumberToObject(response, "temp_probe", temp_probe);
    cJSON_AddNumberToObject(response, "temp_box", temp_box);
    cJSON_AddNumberToObject(response, "temp_evaporator", temp_evaporator);
    cJSON_AddNumberToObject(response, "Total_power", Compressor_power + Evaporator_fan_power + Condenser_fan_power);
    cJSON_AddNumberToObject(response, "Voltage", Voltage);
    cJSON_AddNumberToObject(response, "current", Condenser_fan_current + Evaporator_fan_current + Compressor_current);

    cJSON_AddNumberToObject(response, "Compressor_power", Compressor_power);
    cJSON_AddNumberToObject(response, "Compressor_current", Compressor_current);
    cJSON_AddNumberToObject(response, "Evaporator_fan_power", Evaporator_fan_power);
    cJSON_AddNumberToObject(response, "Evaporator_fan_current", Evaporator_fan_current);
    cJSON_AddNumberToObject(response, "Condenser_fan_power", Condenser_fan_power);
    cJSON_AddNumberToObject(response, "Condenser_fan_current", Condenser_fan_current);

    cJSON_AddBoolToObject(response, "device_485_online", device_485_online);
    cJSON_AddBoolToObject(response, "device_485_compressor", device_485_compressor);
    cJSON_AddBoolToObject(response, "device_485_condenser", device_485_condenser);
    cJSON_AddBoolToObject(response, "device_485_evaporator", device_485_evaporator);

    cJSON_AddBoolToObject(response, "defrost_drip_state", defrost_drip_state);
    cJSON_AddBoolToObject(response, "Fan_state", Fan_state);
    cJSON_AddBoolToObject(response, "defrost_state", defrost_state);
    cJSON_AddBoolToObject(response, "compressor_state", compressor_state);
    cJSON_AddBoolToObject(response, "cabinet_min_temp_warning", cabinet_min_temp_warning);
    cJSON_AddBoolToObject(response, "cabinet_max_temp_warning", cabinet_max_temp_warning);
    cJSON_AddBoolToObject(response, "Evaporation_sensor_fault", Evaporation_sensor_fault);
    cJSON_AddBoolToObject(response, "cabinet_sensor_fault", cabinet_sensor_fault);
    http_success(req, 200, "返回成功", response);

    httpd_resp_send_chunk(req, NULL, 0);

    return ESP_OK;
}

static const httpd_uri_t readData_get = {
    .uri = "/readData",
    .method = HTTP_GET,
    .handler = readdata_get_handler,
    .user_ctx = NULL};

static esp_err_t readMQTT_get_handler(httpd_req_t *req)
{
    cJSON *response = cJSON_CreateObject();
    MQTT_publish_str(response);
    http_success(req, 200, "返回成功", response);

    httpd_resp_send_chunk(req, NULL, 0);

    return ESP_OK;
}

static const httpd_uri_t readmqtt_get = {
    .uri = "/readMQTT",
    .method = HTTP_GET,
    .handler = readMQTT_get_handler,
    .user_ctx = NULL};

static httpd_handle_t start_webserver(void)
{
    httpd_handle_t server = NULL;
    httpd_config_t config = HTTPD_DEFAULT_CONFIG();
    config.lru_purge_enable = true;

    // Start the httpd server
    ESP_LOGI(TAG, "Starting server on port: '%d'", config.server_port);
    if (httpd_start(&server, &config) == ESP_OK)
    {
        // Set URI handlers
        ESP_LOGI(TAG, "Registering URI handlers");
        // httpd_register_uri_handler(server, &hello);
        httpd_register_uri_handler(server, &echo);
        httpd_register_uri_handler(server, &read_get);
        httpd_register_uri_handler(server, &readmqtt_get);
        httpd_register_uri_handler(server, &readData_get);
// httpd_register_uri_handler(server, &ctrl);
#if CONFIG_EXAMPLE_BASIC_AUTH
        httpd_register_basic_auth(server);
#endif
        return server;
    }

    ESP_LOGI(TAG, "Error starting server!");
    return NULL;
}
